<?php

namespace VueRender\Traits;

use VueRender\Render\Build;
use VueRender\Support\Js;

trait HasBase
{
    protected array $classNames = [];
    protected array $styles = [];
    protected array $models = [];
    protected array $states = [];
    protected array $refs = [];
    protected array $attrs = [];
    protected array $methods = [];
    protected string $element;

    /**
     * @param string $key
     * @param mixed $value
     * @return $this
     */
    public function prop(string $key, mixed $value): static
    {
        return $this->props([$key=>$value]);
    }

    /**
     * @param array $props
     * @return $this
     */
    public function props(array $props = []): static
    {
        foreach ($props as $propKey=>$propValue){
            if (is_bool($propValue)){
                $this->attrs(":".$propKey, $propValue?'true':'false');
            }else{
                $this->attrs($propKey, $propValue);
            }
        }
        $this->props = array_merge($this->props?:[],$props);
        return $this;
    }

    /**
     * @param $key
     * @param $value
     * @return $this
     */
    public function attrs($key,$value): static{
        $this->attrs[] = "$key=\"$value\"";
        return $this;
    }



    /**
     * @param string $prop
     * @param string $stateKey
     * @param mixed $default
     * @return $this
     */
    public function bind(string $prop, string $stateKey, mixed $default = null): static
    {
        $bind = Js::bind($stateKey, $default);
        $this->attrs(":".$prop, $bind["value"]);
        $this->state($bind["key"],$bind["default"]);
        return $this;
    }

    /**
     * @param string $prop
     * @param string $methodName 函数名
     * @param string|null $event 函数体
     * @return $this
     */
    public function event(string $prop, string $methodName, string $event = null): static
    {
        $isOnEvent = str_contains($prop,"@")||str_contains($prop,"v-on:");
        $prefix = $isOnEvent?"@":":";
        if ($isOnEvent){
            $key = str_replace(["v-on:","@"],"",$prop);
        }else{
            $key = ltrim(str_replace(["v-bind:"],"",$prop),":");
        }
        $this->attrs($prefix.$key, $methodName);
        $event && $this->method($methodName, $event);
        return $this;
    }

    /**
     * @param string $key
     * @param mixed|null $value
     * @return $this
     */
    public function state(string $key, mixed $value = null): static
    {
        return $this->mergeStates([$key=>$value]);
    }

    /**
     * 设置domRef
     * @param $key
     * @return $this
     */
    public function domRef($key):static
    {
        $this->prop("ref",$key);
        return $this->ref($key,null,true);
    }

    /**
     * 设置vueRef
     * @param $key
     * @param mixed|null $value
     * @return $this
     */
    public function vueRef($key, mixed $value = null):static
    {
        return $this->ref($key,$value);
    }


    /**
     * 设置ref
     * @param string $key
     * @param mixed|null $value
     * @param bool $isDomRef
     * @return $this
     */
    public function ref(string $key, mixed $value = null, bool $isDomRef = false):static
    {
        if (!$isDomRef) {
            if ($value instanceof Build) {
                $value = $value->render();
            }
        }
        $this->refs[$key] = $value;
        return $this;
    }

    /**
     * @param string $name
     * @param string $event 函数体 ()=>{}
     * @return $this
     */
    public function method(string $name, string $event): static
    {
        $methods = $this->methods?:[];
        $methods[] = "const ".$name." = ".$event;
        $this->methods = $methods;
        return $this;
    }

    /**
     * @param array $states
     * @return $this
     */
    protected function mergeStates(array $states = []): static
    {
        $this->states = array_merge($this->states?:[],$states);
        return $this;
    }


    /**
     * @return array
     */
    public function getStates(): array
    {
        return $this->states;
    }

    /**
     * @return array
     */
    public function getMethods(): array
    {
        return $this->methods;
    }

    /**
     * @param array $methods
     * @return $this
     */
    protected function mergeMethods(array $methods): static
    {
        $this->methods = array_merge($this->methods, $methods);
        return $this;
    }


    /**
     * @return array
     */
    public function getRefs(): array
    {
        return $this->refs;
    }

    /**
     * @param array $refs
     * @return $this
     */
    protected function mergeRefs(array $refs): static
    {
        $this->refs = array_merge($this->refs, $refs);
        return $this;
    }

    /**
     * @return string
     */
    public function getElement(): string
    {
        return $this->element;
    }

}
